/**
 * @author mats
 */
function Tooltip(opener, tooltip, options) {
	this.opener = $(opener);
	this.tooltip = $(tooltip).remove();
	$(document.getElementsByTagName("body")[0]).insert(this.tooltip);
	this.tooltip.hide();
	this.options = options;
	this.tooltip._style = {};
	
	this.hideTimer = null;
	this.showTimer = null;
	
	this.setOptions(options);
	this.events();
	this.position();
	if (this.options.ajax) {
		this.href = this.tooltip.innerHTML.strip();
	}
}

Tooltip.prototype = {
	events: function() {
		this.opener.observe("mouseover", this.open.bind(this));
		this.opener.observe("mouseout", this.close.bind(this));
		this.tooltip.observe("mouseover", this.dontCloseTooltip.bind(this));
		this.tooltip.observe("mouseout", this.close.bind(this));
	},
	
	reposition: function() {
		// so we know how much the window has been scrolled
		var scrollOffsets = document.viewport.getScrollOffsets();
		// the size of the viewport
		var viewportDimensions = document.viewport.getDimensions();
		// the size of the tooltip
		var toolTipDimensions = this.tooltip.getDimensions();
		// tooltip's viewportOffset
		var viewportOffset = this.tooltip.viewportOffset()
		// logic is that <var>top</var> should not be less than 0 (zero)
		// <var>top</var> + <var>tooltip.height</var> should not be more than <var>viewportDimensions.height</var> + <var>scrollOffset.top</var>
		// <var>left</var> should be bigger than 0 (ZERO) and <var>left</var> + <var>tooltip.width</var> should be less than <var>viewportDimensions.width</var>
		var top = Math.max(0, 0);
	},
	
	positionInViewport: function(x, y, tooltipSize) {
		// so we know how much the window has been scrolled
		var scrollOffsets = document.viewport.getScrollOffsets();
		var viewportWidth = document.viewport.getWidth();
		var tooltipWidth = tooltipSize.width;
		var left = Math.min(x + this.options.howBigIsTheCursor.width, (scrollOffsets.left + viewportWidth - tooltipWidth) - this.options.howWideIsTheScrollBar );
		return {
			position:"absolute",
			left: Math.max(left, 0) + "px",
			top: Math.max(y, 0) + "px"
		};
	},

	position: function(event) {
		var pos = this.opener.cumulativeOffset();
		var osize = this.opener.getDimensions();
		var tsize = this.tooltip.getDimensions();
		if (this.options.positionRelativeTo === 'mouse' && typeof(event) !== "undefined") {
			var screenX = event.pageX, screenY = event.pageY;
			this.tooltip._style = this.positionInViewport(screenX, screenY, tsize);
			TF.debug(this.tooltip._style, screenX, screenY, event);
		}
		else if (this.options.positionRelativeTo === 'over') {
			this.tooltip._style = {
				position:"absolute",
				left:parseInt(pos.left + this.options.leftOffset - this.options.negativeLeftOffset, 10) + "px",
				top:parseInt(pos.top + this.options.topOffset - this.options.negativeTopOffset, 10) + "px"
			};
		}
		else { //this.options.positionRelativeTo === 'element'
			this.tooltip._style = {
				position:"absolute",
				left: parseInt(pos.left + this.options.leftOffset - this.options.negativeLeftOffset, 10) + "px",
				top: parseInt(pos.top + osize.height + this.options.topOffset - this.options.negativeTopOffset, 10) + "px"
			};
		}
		this.tooltip.setStyle(this.tooltip._style);
	},

	open: function(event) {
		event.stop();
		if (this.hideTimer !== null) {
			clearTimeout(this.hideTimer);
		}
		this.showTimer = setTimeout(function() {
			if (this.options.useEffects) {
				this.effectOpen(event);
			}
			else {
				if (this.options.positionRelativeTo === 'mouse') {
					this.position(event);
				}
				this.options.beforeShow();
				this.tooltip.show();
				this.options.afterShow();
			}
		}.bind(this), this.options.showTimeout);
		this.position();
	},
	
	dontCloseTooltip:function(event) {
		event.stop();
		if (this.hideTimer !== null) {
			clearTimeout(this.hideTimer);
		}
		if (this.showTimer !== null) {
			clearTimeout(this.showTimer);
		}
	},
	
	close: function(event) {
		event.stop();
		if (this.showTimer !== null) {
			clearTimeout(this.showTimer);
		}
		this.hideTimer = setTimeout(function() {
			if (this.options.useEffects) {
				this.effectClose();
			}
			else {
				this.options.beforeHide();
				this.tooltip.hide();
				this.options.afterHide();
			}
		}.bind(this), this.options.hideTimeout);
	},
	
	effectOpen: function(event) {
		if (this.options.positionRelativeTo === 'mouse') {
			this.position(event);
		}
		new Effect.Appear(this.tooltip, {
			duration:0.3,
			beforeStart:this.options.beforeShow.bind(this),
			afterFinish:this.options.afterShow.bind(this)
		});
		if (this.options.adjustPositionAfterShow) {
			this.reposition();
		}
	},
	
	effectClose: function() {
		new Effect.Fade(this.tooltip, {
			duration:0.3,
			beforeStart:this.options.beforeHide.bind(this),
			afterFinish:this.options.afterHide.bind(this)
		});
	},
	
	setOptions: function(options) {
		this.options = {
			showTimeout:          	0,
			hideTimeout:          	250,
			beforeShow:           	Prototype.emptyFunction,
			afterShow:            	Prototype.emptyFunction,
			beforeHide:           	Prototype.emptyFunction,
			afterHide:            	Prototype.emptyFunction,
			leftOffset:          		0,
			topOffset:            	0,
			negativeLeftOffset:   	0,
			negativeTopOffset:    	0,
			useEffects:           	false,
			zIndex:               	5000,
			ajax:										false,
			ajaxContentLoaded:			false,
			positionRelativeTo:			'element', // 'mouse', 'over'
			howBigIsTheCursor: 			{
				height:8,
				width:8
			},
			howWideIsTheScrollBar: 	42,
			adjustPositionAfterShow:false
		};
		Object.extend(this.options, options || {});
		this.options.beforeShow = this.options.beforeShow.bind(this);
		this.options.afterShow = this.options.afterShow.bind(this);
		this.options.beforeHide = this.options.beforeHide.bind(this);
		this.options.afterHide = this.options.afterHide.bind(this);
	}
};
